﻿package idv.cjcat.shintaz.tests.cases {
	import asunit.framework.TestCase;
	import idv.cjcat.shintaz.compiler.scanner.IScanner;
	import idv.cjcat.shintaz.compiler.scanner.Scanner;
	import idv.cjcat.shintaz.compiler.scanner.Token;
	import idv.cjcat.shintaz.compiler.scanner.TokenType;
	
	public class ScannerTest extends TestCase {
		
		public function ScannerTest(testMethod:String = null) {
			super(testMethod);
		}
		
		public function testWhiteSpaces():void {
			var scanner:IScanner;
			var token:Token;
			var code:String;
			
			code= "abc \n def \n\t\n  \tghi \r\n \n \n jkl";
			scanner = new Scanner(code);
			
			token = scanner.getToken();
			assertEquals(token.type, TokenType.ID);
			assertEquals("abc", token.value);
			
			token = scanner.getToken();
			assertEquals(TokenType.ID, token.type);
			assertEquals("def", token.value);
			
			token = scanner.getToken();
			assertEquals(TokenType.ID, token.type);
			assertEquals("ghi", token.value);
			
			token = scanner.getToken();
			assertEquals(TokenType.ID, token.type);
			assertEquals("jkl", token.value);
			
			token = scanner.getToken();
			assertNull(token);
		}
		
		public function testNumbers():void {
			var scanner:IScanner;
			var token:Token;
			var code:String;
			
			code = "abc \n 1234 \n\n 1234.1234 \n 0.1234 .1234 0xaBc";
			scanner = new Scanner(code);
			
			token = scanner.getToken();
			assertEquals(TokenType.ID, token.type);
			assertEquals(token.value, "abc");
			
			token = scanner.getToken();
			assertEquals(TokenType.NUMBER, token.type);
			assertEquals(1234, token.value);
			
			token = scanner.getToken();
			assertEquals(TokenType.NUMBER, token.type);
			assertEquals(1234.1234, token.value);
			
			token = scanner.getToken();
			assertEquals(TokenType.NUMBER, token.type);
			assertEquals(0.1234, token.value);
			
			token = scanner.getToken();
			assertEquals(TokenType.NUMBER, token.type);
			assertEquals(.1234, token.value);
			
			token = scanner.getToken();
			assertEquals(TokenType.NUMBER, token.type);
			assertEquals(0xABC, token.value);
			
			token = scanner.getToken();
			assertNull(token);
		}
		
		public function testStrings():void {
			var scanner:IScanner;
			var token:Token;
			var code:String;
			
			code = "\"hello world\"  \"tab \\t\"   \"\nabc\n\"";
			scanner = new Scanner(code);
			
			token = scanner.getToken();
			assertEquals(TokenType.STRING, token.type);
			assertEquals("hello world", token.value);
			
			token = scanner.getToken();
			assertEquals(TokenType.STRING, token.type);
			assertEquals("tab \t", token.value);
			
			token = scanner.getToken();
			assertEquals(TokenType.STRING, token.type);
			assertEquals("\nabc\n", token.value);
			
			token = scanner.getToken();
			assertNull(token);
		}
		
		public function testComments():void {
			var scanner:IScanner;
			var token:Token;
			var code:String;
			
			code = "abc //comment \n def /*multi \n line \n comment*/ ghi";
			scanner = new Scanner(code);
			
			token = scanner.getToken();
			assertEquals(TokenType.ID, token.type);
			assertEquals("abc", token.value);
			
			token = scanner.getToken();
			assertEquals(TokenType.ID, token.type);
			assertEquals("def", token.value);
			
			token = scanner.getToken();
			assertEquals(TokenType.ID, token.type);
			assertEquals("ghi", token.value);
			
			token = scanner.getToken();
			assertNull(token);
		}
		
		public function testIDs():void {
			var scanner:IScanner;
			var token:Token;
			var code:String;
			
			code = "abc _abc $abc abc_$1234";
			scanner = new Scanner(code);
			
			token = scanner.getToken();
			assertEquals(token.type, TokenType.ID);
			assertEquals("abc", token.value);
			
			token = scanner.getToken();
			assertEquals(token.type, TokenType.ID);
			assertEquals("_abc", token.value);
			
			token = scanner.getToken();
			assertEquals(token.type, TokenType.ID);
			assertEquals("$abc", token.value);
			
			token = scanner.getToken();
			assertEquals(token.type, TokenType.ID);
			assertEquals("abc_$1234", token.value);
			
			token = scanner.getToken();
			assertNull(token);
		}
		
		public function testKeywords():void {
			var scanner:IScanner;
			var token:Token;
			var code:String;
			
			code = "";
			code += "break \n";
			code += "case \n";
			code += "continue \n";
			code += "default \n";
			code += "delete \n";
			code += "do \n";
			code += "else \n";
			code += "for \n";
			code += "function \n";
			code += "if \n";
			code += "new \n";
			code += "return \n";
			code += "switch \n";
			code += "this \n";
			code += "var \n";
			code += "while \n";
			code += "true \n";
			code += "false \n";
			code += "null \n";
			code += "undefined \n";
			
			scanner = new Scanner(code);
			
			assertEquals(Token.BREAK, scanner.getToken());
			assertEquals(Token.CASE, scanner.getToken());
			assertEquals(Token.CONTINUE, scanner.getToken());
			assertEquals(Token.DEFAULT, scanner.getToken());
			assertEquals(Token.DELETE, scanner.getToken());
			assertEquals(Token.DO, scanner.getToken());
			assertEquals(Token.ELSE, scanner.getToken());
			assertEquals(Token.FOR, scanner.getToken());
			assertEquals(Token.FUNCTION, scanner.getToken());
			assertEquals(Token.IF, scanner.getToken());
			assertEquals(Token.NEW, scanner.getToken());
			assertEquals(Token.RETURN, scanner.getToken());
			assertEquals(Token.SWITCH, scanner.getToken());
			assertEquals(Token.THIS, scanner.getToken());
			assertEquals(Token.VAR, scanner.getToken());
			assertEquals(Token.WHILE, scanner.getToken());
			assertEquals(Token.TRUE, scanner.getToken());
			assertEquals(Token.FALSE, scanner.getToken());
			assertEquals(Token.NULL, scanner.getToken());
			assertEquals(Token.UNDEFINED, scanner.getToken());
			
			token = scanner.getToken();
			assertNull(token);
		}
		
		public function testDelimiters():void {
			var scanner:IScanner;
			var token:Token;
			var code:String;
			
			code = "()[]{},.?:;";
			scanner = new Scanner(code);
			
			assertEquals(Token.PAREN_L, scanner.getToken());
			assertEquals(Token.PAREN_R, scanner.getToken());
			assertEquals(Token.BRACK_L, scanner.getToken());
			assertEquals(Token.BRACK_R, scanner.getToken());
			assertEquals(Token.BRACE_L, scanner.getToken());
			assertEquals(Token.BRACE_R, scanner.getToken());
			assertEquals(Token.COMMA, scanner.getToken());
			assertEquals(Token.DOT, scanner.getToken());
			assertEquals(Token.QUESTION, scanner.getToken());
			assertEquals(Token.COLON, scanner.getToken());
			assertEquals(Token.S_COLON, scanner.getToken());
			
			token = scanner.getToken();
			assertNull(token);
		}
		
		public function testOperators():void {
			var scanner:IScanner;
			var token:Token;
			var code:String;
			
			code = "";
			code += "+ - * / += -= *= /= ++ -- \n";
			code += "& && | || ^ ! < > << >> <<< >>> \n";
			code += "&= |= ^= != <= >= <<= >>= <<<= >>>=";
			
			scanner = new Scanner(code);
			
			assertEquals(Token.PLUS, scanner.getToken());
			assertEquals(Token.MINUS, scanner.getToken());
			assertEquals(Token.MUL, scanner.getToken());
			assertEquals(Token.DIV, scanner.getToken());
			assertEquals(Token.ASSIGN_PLUS, scanner.getToken());
			assertEquals(Token.ASSIGN_MINUS, scanner.getToken());
			assertEquals(Token.ASSIGN_MUL, scanner.getToken());
			assertEquals(Token.ASSIGN_DIV, scanner.getToken());
			assertEquals(Token.INCRE, scanner.getToken());
			assertEquals(Token.DECRE, scanner.getToken());
			
			assertEquals(Token.BIT_AND, scanner.getToken());
			assertEquals(Token.AND, scanner.getToken());
			assertEquals(Token.BIT_OR, scanner.getToken());
			assertEquals(Token.OR, scanner.getToken());
			assertEquals(Token.BIT_XOR, scanner.getToken());
			assertEquals(Token.NOT, scanner.getToken());
			assertEquals(Token.LT, scanner.getToken());
			assertEquals(Token.GT, scanner.getToken());
			assertEquals(Token.SHIFT_L, scanner.getToken());
			assertEquals(Token.SHIFT_R, scanner.getToken());
			assertEquals(Token.USHIFT_L, scanner.getToken());
			assertEquals(Token.USHIFT_R, scanner.getToken());
			
			assertEquals(Token.ASSIGN_BIT_AND, scanner.getToken());
			assertEquals(Token.ASSIGN_BIT_OR, scanner.getToken());
			assertEquals(Token.ASSIGN_BIT_XOR, scanner.getToken());
			assertEquals(Token.NEQ, scanner.getToken());
			assertEquals(Token.LE, scanner.getToken());
			assertEquals(Token.GE, scanner.getToken());
			assertEquals(Token.ASSIGN_SHIFT_L, scanner.getToken());
			assertEquals(Token.ASSIGN_SHIFT_R, scanner.getToken());
			assertEquals(Token.ASSIGN_USHIFT_L, scanner.getToken());
			assertEquals(Token.ASSIGN_USHIFT_R, scanner.getToken());
			
			token = scanner.getToken();
			assertNull(token);
		}
		
		public function testCode():void {
			var scanner:IScanner;
			var token:Token;
			var code:String;
			
			code = "";
			code += "var count = 100;						\n";
			code += "var str = \"pika is fat\";				\n";
			code += "for (var i = 0; i < count; i++) {		\n";
			code += "	doSomething();						\n";
			code += "	if (true) {							\n";
			code += "		hoho(1, 2, 3);					\n";
			code += "		this.x = 10;					\n";
			code += "		continue;						\n";
			code += "		break;							\n";
			code += "	}									\n";
			code += "}										\n";
			code += "i = (true)?(1+2):(3);					\n";
			code += "switch (key) {							\n";
			code += "	case 3:								\n";
			code += "		break;							\n";
			code += "	default:							\n";
			code += "		break;							\n";
			code += "}										\n";
			code += "while (false) i--;						\n";
			code += "function mul(a, b) {					\n";
			code += "	return a + b;						\n";
			code += "}										\n";
			
			scanner = new Scanner(code);
			
			//var
			assertEquals(Token.VAR, scanner.getToken());
			
			//count
			token = scanner.getToken();
			assertEquals(TokenType.ID, token.type);
			assertEquals("count", token.value);
			
			//=
			assertEquals(Token.ASSIGN, scanner.getToken());
			
			//100
			token = scanner.getToken();
			assertEquals(TokenType.NUMBER, token.type);
			assertEquals(100, token.value);
			
			//;
			assertEquals(Token.S_COLON, scanner.getToken());
			
			//var
			assertEquals(Token.VAR, scanner.getToken());
			
			//str
			token = scanner.getToken();
			assertEquals(TokenType.ID, token.type);
			assertEquals("str", token.value);
			
			//=
			assertEquals(Token.ASSIGN, scanner.getToken());
			
			//"pika is fat"
			token = scanner.getToken();
			assertEquals(TokenType.STRING, token.type);
			assertEquals("pika is fat", token.value);
			
			//;
			assertEquals(Token.S_COLON, scanner.getToken());
			
			//for
			assertEquals(Token.FOR, scanner.getToken());
			
			//(
			assertEquals(Token.PAREN_L, scanner.getToken());
			
			//var
			assertEquals(Token.VAR, scanner.getToken());
			
			//i
			token = scanner.getToken();
			assertEquals(TokenType.ID, token.type);
			assertEquals("i", token.value);
			
			//=
			assertEquals(Token.ASSIGN, scanner.getToken());
			
			//0
			token = scanner.getToken();
			assertEquals(TokenType.NUMBER, token.type);
			assertEquals(0, token.value);
			
			//;
			assertEquals(Token.S_COLON, scanner.getToken());
			
			//i
			token = scanner.getToken();
			assertEquals(TokenType.ID, token.type);
			assertEquals("i", token.value);
			
			//<
			assertEquals(Token.LT, scanner.getToken());
			
			//count
			token = scanner.getToken();
			assertEquals(TokenType.ID, token.type);
			assertEquals("count", token.value);
			
			//;
			assertEquals(Token.S_COLON, scanner.getToken());
			
			//i
			token = scanner.getToken();
			assertEquals(TokenType.ID, token.type);
			assertEquals("i", token.value);
			
			//++
			assertEquals(Token.INCRE, scanner.getToken());
			
			//)
			assertEquals(Token.PAREN_R, scanner.getToken());
			
			//{
			assertEquals(Token.BRACE_L, scanner.getToken());
			
			//doSomething
			token = scanner.getToken();
			assertEquals(TokenType.ID, token.type);
			assertEquals("doSomething", token.value);
			
			//(
			assertEquals(Token.PAREN_L, scanner.getToken());
			
			//)
			assertEquals(Token.PAREN_R, scanner.getToken());
			
			//;
			assertEquals(Token.S_COLON, scanner.getToken());
			
			//if
			assertEquals(Token.IF, scanner.getToken());
			
			//(
			assertEquals(Token.PAREN_L, scanner.getToken());
			
			//true
			assertEquals(Token.TRUE, scanner.getToken());
			
			//)
			assertEquals(Token.PAREN_R, scanner.getToken());
			
			//{
			assertEquals(Token.BRACE_L, scanner.getToken());
			
			//hoho
			token = scanner.getToken();
			assertEquals(TokenType.ID, token.type);
			assertEquals("hoho", token.value);
			
			//(
			assertEquals(Token.PAREN_L, scanner.getToken());
			
			//1
			token = scanner.getToken();
			assertEquals(TokenType.NUMBER, token.type);
			assertEquals(1, token.value);
			
			//,
			assertEquals(Token.COMMA, scanner.getToken());
			
			//2
			token = scanner.getToken();
			assertEquals(TokenType.NUMBER, token.type);
			assertEquals(2, token.value);
			
			//,
			assertEquals(Token.COMMA, scanner.getToken());
			
			//3
			token = scanner.getToken();
			assertEquals(TokenType.NUMBER, token.type);
			assertEquals(3, token.value);
			
			//)
			assertEquals(Token.PAREN_R, scanner.getToken());
			
			//;
			assertEquals(Token.S_COLON, scanner.getToken());
			
			//this
			assertEquals(Token.THIS, scanner.getToken());
			
			//.
			assertEquals(Token.DOT, scanner.getToken());
			
			//x
			token = scanner.getToken();
			assertEquals(TokenType.ID, token.type);
			assertEquals("x", token.value);
			
			//=
			assertEquals(Token.ASSIGN, scanner.getToken());
			
			//10
			token = scanner.getToken();
			assertEquals(TokenType.NUMBER, token.type);
			assertEquals(10, token.value);
			
			//;
			assertEquals(Token.S_COLON, scanner.getToken());
			
			//continue
			assertEquals(Token.CONTINUE, scanner.getToken());
			
			//;
			assertEquals(Token.S_COLON, scanner.getToken());
			
			//break
			assertEquals(Token.BREAK, scanner.getToken());
			
			//;
			assertEquals(Token.S_COLON, scanner.getToken());
			
			//}
			assertEquals(Token.BRACE_R, scanner.getToken());
			
			//}
			assertEquals(Token.BRACE_R, scanner.getToken());
			
			//i
			token = scanner.getToken();
			assertEquals(TokenType.ID, token.type);
			assertEquals("i", token.value);
			
			//=
			assertEquals(Token.ASSIGN, scanner.getToken());
			
			//(
			assertEquals(Token.PAREN_L, scanner.getToken());
			
			//true
			assertEquals(Token.TRUE, scanner.getToken());
			
			//)
			assertEquals(Token.PAREN_R, scanner.getToken());
			
			//?
			assertEquals(Token.QUESTION, scanner.getToken());
			
			//(
			assertEquals(Token.PAREN_L, scanner.getToken());
			
			//1
			token = scanner.getToken();
			assertEquals(TokenType.NUMBER, token.type);
			assertEquals(1, token.value);
			
			//+
			assertEquals(Token.PLUS, scanner.getToken());
			
			//2
			token = scanner.getToken();
			assertEquals(TokenType.NUMBER, token.type);
			assertEquals(2, token.value);
			
			//)
			assertEquals(Token.PAREN_R, scanner.getToken());
			
			//:
			assertEquals(Token.COLON, scanner.getToken());
			
			//(
			assertEquals(Token.PAREN_L, scanner.getToken());
			
			//3
			token = scanner.getToken();
			assertEquals(TokenType.NUMBER, token.type);
			assertEquals(3, token.value);
			
			//)
			assertEquals(Token.PAREN_R, scanner.getToken());
			
			//;
			assertEquals(Token.S_COLON, scanner.getToken());
			
			//switch
			assertEquals(Token.SWITCH, scanner.getToken());
			
			//(
			assertEquals(Token.PAREN_L, scanner.getToken());
			
			//key
			token = scanner.getToken();
			assertEquals(TokenType.ID, token.type);
			assertEquals("key", token.value);
			
			//)
			assertEquals(Token.PAREN_R, scanner.getToken());
			
			//{
			assertEquals(Token.BRACE_L, scanner.getToken());
			
			//case
			assertEquals(Token.CASE, scanner.getToken());
			
			//3
			token = scanner.getToken();
			assertEquals(TokenType.NUMBER, token.type);
			assertEquals(3, token.value);
			
			//:
			assertEquals(Token.COLON, scanner.getToken());
			
			//break
			assertEquals(Token.BREAK, scanner.getToken());
			
			//;
			assertEquals(Token.S_COLON, scanner.getToken());
			
			//default
			assertEquals(Token.DEFAULT, scanner.getToken());
			
			//:
			assertEquals(Token.COLON, scanner.getToken());
			
			//break
			assertEquals(Token.BREAK, scanner.getToken());
			
			//;
			assertEquals(Token.S_COLON, scanner.getToken());
			
			//}
			assertEquals(Token.BRACE_R, scanner.getToken());
			
			//while
			assertEquals(Token.WHILE, scanner.getToken());
			
			//(
			assertEquals(Token.PAREN_L, scanner.getToken());
			
			//false
			assertEquals(Token.FALSE, scanner.getToken());
			
			//)
			assertEquals(Token.PAREN_R, scanner.getToken());
			
			//i
			token = scanner.getToken();
			assertEquals(TokenType.ID, token.type);
			assertEquals("i", token.value);
			
			//--
			assertEquals(Token.DECRE, scanner.getToken());
			
			//;
			assertEquals(Token.S_COLON, scanner.getToken());
			
			//function
			assertEquals(Token.FUNCTION, scanner.getToken());
			
			//mul
			token = scanner.getToken();
			assertEquals(TokenType.ID, token.type);
			assertEquals("mul", token.value);
			
			//(
			assertEquals(Token.PAREN_L, scanner.getToken());
			
			//a
			token = scanner.getToken();
			assertEquals(TokenType.ID, token.type);
			assertEquals("a", token.value);
			
			//,
			assertEquals(Token.COMMA, scanner.getToken());
			
			//b
			token = scanner.getToken();
			assertEquals(TokenType.ID, token.type);
			assertEquals("b", token.value);
			
			//)
			assertEquals(Token.PAREN_R, scanner.getToken());
			
			//{
			assertEquals(Token.BRACE_L, scanner.getToken());
			
			//return
			assertEquals(Token.RETURN, scanner.getToken());
			
			//a
			token = scanner.getToken();
			assertEquals(TokenType.ID, token.type);
			assertEquals("a", token.value);
			
			//+
			assertEquals(Token.PLUS, scanner.getToken());
			
			//b
			token = scanner.getToken();
			assertEquals(TokenType.ID, token.type);
			assertEquals("b", token.value);
			
			//;
			assertEquals(Token.S_COLON, scanner.getToken());
			
			//}
			assertEquals(Token.BRACE_R, scanner.getToken());
			
			assertNull(scanner.getToken());
		}
	}
}